package cn.touch.jmx.oome;

import java.util.Vector;

/**
 * Created by <a href="mailto:88052350@qq.com">chengqiang.han</a> on 2022/12/1.
 * <p>
 * https://blog.csdn.net/weixin_70730532/article/details/124732635
 *
 *
 * 2.消耗 Cpu 命令
 * 因为是消耗 Cpu，因此在配置 Jvm 时使用了最少的 64M 进行启动，如下
 * java -XX:InitialHeapSize=64m -XX:MaxHeapSize=64m -XX:NewSize=32m -XX:MaxNewSize=32m -XX:+UseParNewG
 *
 *3.消耗内存命令
 * java -XX:InitialHeapSize=4096m -XX:MaxHeapSize=4096m -XX:NewSize=3072m -XX:MaxNewSize=3072m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:PretenureSizeThreshold=500m -cp "." ResouceManageService -m 1 &
 * 参数说明：-m 表示消耗内存，无此参数表示消耗 Cpu， -m 后面的数字 1 表明消耗 1G 内存
 * 原理： 启动命令时申请最大堆内存 4096Mb,新生代 3072M，程序在启动时将产生 -m 后面数字的内存的数据放在 list 中，然后申请完后，就一直休眠。这样来达到消耗内存不释放的目的。因此-m 后面的数据不能超过新生代配置的内存的最大值，如果需要超过，就把最大内存和新生代的内存配置增加后再启动，如需要一次性消号 6Gb 内存，可用如下示例配置：
 * java -XX:InitialHeapSize=8192m -XX:MaxHeapSize=8192m -XX:NewSize=7168m -XX:MaxNewSize=7168m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:PretenureSizeThreshold=500m -cp "." ResouceManageService -m 1 &
 * XX:PretenureSizeThreshold 设置成了 500MB，是因为我的代码的这一句，byte b1[] = new byte[104857600]; //100M，里面一次申请内存就 100M，为避免申请的对象进入老年代，将 XX:PretenureSizeThreshold 设置调大了
 * 以上命令，可考虑放在shell中保存，以方便执行，如：
 * ####vi start-cpu.sh
 * #!/bin/sh
 * java -XX:InitialHeapSize=64m -XX:MaxHeapSize=64m -XX:NewSize=32m -XX:MaxNewSize=32m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:PretenureSizeThreshold=10m -cp "." ResouceManageService &
 *
 */
public class ResouceManageService {

    //是否跑消耗内存代码的标记,默认否，即跑消耗Cpu的代码
    private static boolean memConsume = false;

    public static void main(String[] args) throws Exception {

        final ResouceManageService service = new ResouceManageService();

        int num = 1;

        for (int i = 0; i < args.length; i++) {
            //指定-m表明跑消耗内存，指定-c或不指定为消耗Cpu，
            if ("-c".equals(args[i])) {

            } else if ("-m".equals(args[i])) {
                memConsume = true;
                num = Integer.parseInt(args[i + 1]);
                i++;
            }

        }

        if (memConsume) {
            service.memConsume(num);
        } else {

            service.cpuConsume();

        }

    }

    //只内存消耗调用这个方法
    @SuppressWarnings("unchecked")
    public void memConsume(int num) {
        //执行一个for循环进行新生代内存的申请，共消耗num数量GB
        for (int i = 0; i < num * 10; i++) {
            @SuppressWarnings("rawtypes")
            Vector v = new Vector();
            byte b1[] = new byte[104857600]; //100M
            v.add(b1);
          /*System.out.println(v);
          Runtime rt = Runtime.getRuntime();
          System.out.println("free memory"+ rt.freeMemory() );*/
        }
        //内存消耗申请完后，执行死循环休眠，让JVM一直占用申请到的内存，达到一直占用num数量GB的效果
        while (true) {
            try {
                Thread.sleep(3600000l);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    //cpu消耗方法
    public void cpuConsume() {
        // 角度的分割
        final double SPLIT = 0.01;
        //
        // 2PI分割的次数，也就是2/0.01个，正好是一周
        final int COUNT = (int) (2 / SPLIT);
        final double PI = Math.PI;
        // 时间间隔
        final int INTERVAL = 200;
        long[] busySpan = new long[COUNT];
        long[] idleSpan = new long[COUNT];
        int half = INTERVAL / 2;
        double radian = 0.0;
        for (int i = 0; i < COUNT; i++) {
            busySpan[i] = (long) (half + (Math.sin(PI * radian) * half));
            idleSpan[i] = INTERVAL - busySpan[i];
            radian += SPLIT;
        }
        long startTime = 0;
        int j = 0;
        while (true) {
            j = j % COUNT;
            startTime = System.currentTimeMillis();
            while (System.currentTimeMillis() - startTime < busySpan[j])
                ;
            try {
                //这里的if控制可以注解掉，让Thread.sleep(idleSpan[j])一直执行。
                //我这里加了if控制是因为希望Cpu一直保存在70%以上工作的效果(小于70不sleep)，If注解掉将以正弦曲线的趋势使用Cpu
                if (idleSpan[j] < 70) {
                    Thread.sleep(idleSpan[j]);
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            j++;
        }
    }

}
